//功能：根据触发信号从FIFO接口读出一幅图像，可选择是否添加图像包头16'h55AA
//注意：一个像素占用DWIDTH bits
module fifo_port_img_rd#(
parameter WIDTH      = 480,
parameter HEIGHT     = 320,
parameter DWIDTH     = 16 ,
parameter HEAD_INDEX = 16'h55AA,
parameter ADD_HEAD   = 1 //决定是否在图像数据开头插入数据包头：0x55AA ，1：插入 0：不插入
    )(
    input               clk,    //工作时钟
    input               rst_n,  //异步复位，低有效
    //读触发，高有效
    input               read_trig,//触发读一帧的脉冲信号，高有效，持续一个clk高电平即可
    output              read_done,//触发读一帧完成标志信号，持续一个clk高电平
    //FIFO读接口
    output              rd_req,       //读请求
    input               rd_empty,     //FIFO空信号
    input  [DWIDTH-1:0] rd_q,         //读出的数据
    //图像输出接口
    input               source_ready,//可输出数据标志，高有效
    output              source_valid,//数据有效标志，高有效
    output [DWIDTH-1:0] source_data  //输出的图像数据
    );
localparam TOTAL_PIXEL = WIDTH*HEIGHT;
localparam IDLE = 2'b00;
localparam HEAD = 2'b01;//添加包头状态
localparam DLY  = 2'b11;//为包头数据输出留一拍缓冲，便于数据在包头数据和图像数据之间切换输出
localparam IMG  = 2'b10;//输出图像数据状态
reg        source_valid_r;//数据有效标志，高有效
reg [DWIDTH-1:0] source_data_r; //输出的图像数据
reg        read_done_r;   //触发读一帧完成信号，高有效，低电平代表忙
reg [31:0] pix_cnt;       //读出的图像数据计数器
reg [1:0]  state;         //状态寄存器
assign source_valid = source_valid_r;
assign source_data  = (state == DLY)?source_data_r:rd_q;//数据在包头数据和图像数据之间切换输出
//assign source_data  = (state == DLY)?source_data_r:{5'b00000,6'b111111,5'b00000};//数据在包头数据和图像数据之间切换输出
assign read_done    = read_done_r;
assign rd_req       = source_ready && !rd_empty && (state == IMG);//非空并且处于读出图像数据状态时才拉高读请求
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
    source_valid_r <= 1'b0;
    source_data_r  <= 16'd0;
    read_done_r    <= 1'b1;
    state          <= IDLE;
    pix_cnt        <= 0;
end
else begin
    case(state)
    IDLE:begin
        state          <= read_trig?(ADD_HEAD?HEAD:DLY):IDLE;//检测到触发后，根据是否添加数据包头决定是否进入HEAD态
        read_done_r    <= 1'b0;//read_done_r拉低，以保证read_done_r只持续一个时钟高电平
        pix_cnt        <= 0;//像素计数器清零
        source_valid_r <= 1'b0;
        source_data_r  <= 16'd0;
    end
    HEAD:begin
        state          <= source_ready?DLY:HEAD;
        pix_cnt        <= 0;//像素计数器保持为0
        source_valid_r <= source_ready;
        source_data_r  <= HEAD_INDEX;//输出包头数据
    end
    DLY:begin
        state          <= IMG;//进入读出图像数据的状态
        pix_cnt        <= 0;//像素计数器保持为0
        source_valid_r <= 1'b0;
        source_data_r  <= source_data_r;
    end
    IMG:begin
        state          <= (rd_req && (pix_cnt == TOTAL_PIXEL-1))?IDLE:IMG;//读出个数等于TOTAL_PIXEL-1并且rd_req为高时代表读出图像最后一个数据
        pix_cnt        <= rd_req?pix_cnt+1:pix_cnt;//读一次FIFO计数器自增1
        source_valid_r <= rd_req;
        source_data_r  <= source_data_r;
        read_done_r    <= (rd_req && (pix_cnt == TOTAL_PIXEL-1));//读出图像最后一个数据时把read_done_r拉高
    end
    endcase
end
end
endmodule